package gu.simplemq.json;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;

import static com.google.common.base.Preconditions.*;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * {@link JSONObject}装饰类
 * @author guyadong
 *
 */
public class JSONObjectDecorator extends JSONObject {
	private static final Logger logger = LoggerFactory.getLogger(JSONObjectDecorator.class);

	private static final long serialVersionUID = 1L;
	private final JSONObject delegate;
	public JSONObjectDecorator(JSONObject delegate) {
		this.delegate = checkNotNull(delegate,"delegate is null");
	}
	public JSONObjectDecorator(Map<String, Object> delegate) {
		this(new JSONObject(checkNotNull(delegate,"delegate is null")));
	}
	public JSONObject getDelegate() {
		return delegate;
	}
	public int size() {
		return delegate.size();
	}
	public boolean isEmpty() {
		return delegate.isEmpty();
	}
	public boolean containsKey(Object key) {
		return delegate.containsKey(key);
	}
	public boolean containsValue(Object value) {
		return delegate.containsValue(value);
	}
	public Object get(Object key) {
		return delegate.get(key);
	}
	public JSONObject getJSONObject(String key) {
		return delegate.getJSONObject(key);
	}
	public JSONArray getJSONArray(String key) {
		return delegate.getJSONArray(key);
	}
	public <T> T getObject(String key, Class<T> clazz) {
		return delegate.getObject(key, clazz);
	}
	public <T> T getObject(String key, Type type) {
		return delegate.getObject(key, type);
	}
	@SuppressWarnings("rawtypes")
	public <T> T getObject(String key, TypeReference typeReference) {
		return delegate.getObject(key, typeReference);
	}
	public Boolean getBoolean(String key) {
		return delegate.getBoolean(key);
	}
	public byte[] getBytes(String key) {
		return delegate.getBytes(key);
	}
	public boolean getBooleanValue(String key) {
		return delegate.getBooleanValue(key);
	}
	public Byte getByte(String key) {
		return delegate.getByte(key);
	}
	public byte getByteValue(String key) {
		return delegate.getByteValue(key);
	}
	public Short getShort(String key) {
		return delegate.getShort(key);
	}
	public short getShortValue(String key) {
		return delegate.getShortValue(key);
	}
	public Integer getInteger(String key) {
		return delegate.getInteger(key);
	}
	public int getIntValue(String key) {
		return delegate.getIntValue(key);
	}
	public Long getLong(String key) {
		return delegate.getLong(key);
	}
	public long getLongValue(String key) {
		return delegate.getLongValue(key);
	}
	public Float getFloat(String key) {
		return delegate.getFloat(key);
	}
	public float getFloatValue(String key) {
		return delegate.getFloatValue(key);
	}
	public Double getDouble(String key) {
		return delegate.getDouble(key);
	}
	public double getDoubleValue(String key) {
		return delegate.getDoubleValue(key);
	}
	public BigDecimal getBigDecimal(String key) {
		return delegate.getBigDecimal(key);
	}
	public BigInteger getBigInteger(String key) {
		return delegate.getBigInteger(key);
	}
	public String getString(String key) {
		return delegate.getString(key);
	}
	public Date getDate(String key) {
		return delegate.getDate(key);
	}
	public java.sql.Date getSqlDate(String key) {
		return (java.sql.Date)delegate.getSqlDate(key);
	}
	public Timestamp getTimestamp(String key) {
		return (Timestamp) delegate.getTimestamp(key);
	}
	public Object put(String key, Object value) {
		return delegate.put(key, value);
	}
	public JSONObject fluentPut(String key, Object value) {
		return delegate.fluentPut(key, value);
	}
	public void putAll(Map<? extends String, ? extends Object> m) {
		delegate.putAll(m);
	}
	public JSONObject fluentPutAll(Map<? extends String, ? extends Object> m) {
		return delegate.fluentPutAll(m);
	}
	public void clear() {
		delegate.clear();
	}
	public JSONObject fluentClear() {
		return delegate.fluentClear();
	}
	public Object remove(Object key) {
		return delegate.remove(key);
	}
	public JSONObject fluentRemove(Object key) {
		return delegate.fluentRemove(key);
	}
	public Set<String> keySet() {
		return delegate.keySet();
	}
	public Collection<Object> values() {
		return delegate.values();
	}
	public Set<java.util.Map.Entry<String, Object>> entrySet() {
		return delegate.entrySet();
	}
	@Override
	public JSONObject clone() {
		return (JSONObject) delegate.clone();
	}
	public boolean equals(Object obj) {
		return delegate.equals(obj);
	}
	public int hashCode() {
		return delegate.hashCode();
	}
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		return delegate.invoke(proxy, method, args);
	}
	public Map<String, Object> getInnerMap() {
		return delegate.getInnerMap();
	}
	public String toString() {
		return delegate.toString();
	}
	public String toJSONString() {
		return delegate.toJSONString();
	}
	public void writeJSONString(Appendable appendable) {
		delegate.writeJSONString(appendable);
	}
	public <T> T toJavaObject(Class<T> clazz) {
		return delegate.toJavaObject(clazz);
	}
	public <T> T toJavaObject(Type type) {
		return delegate.toJavaObject(type);
	}
	@SuppressWarnings("rawtypes")
	public <T> T toJavaObject(TypeReference typeReference) {
		return delegate.toJavaObject(typeReference);
	}
	///////////////////////
	
	/**
	 * 代理 {@link JSONObject#getJSONObject(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link JSONObject}对象，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public JSONObject getJSONObjectOrNull(String key){
		try {
			return getJSONObject(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getJSONArray(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link JSONArray}对象，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public JSONArray getJSONArrayOrNull(String key){
		try {
			return getJSONArray(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getObject(String, Type)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取指定类型{@code type}的值，
	 * 解析失败则返回{@code null}
	 * @param key
	 * @param type
	 */
	public <T> T getObjectOrNull(String key,Type type){
		try {
			return getObject(key,type);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getObject(String, Type)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取指定类型{@code clazz}的值，
	 * 解析失败则返回{@code null}
	 * @param key
	 * @param clazz
	 */
	public <T> T getObjectOrNull(String key,Class<T> clazz){
		try {
			return getObject(key,clazz);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getString(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取字符串，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public String getStringOrNull(String key){
		try {
			return getString(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getInteger(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取整数({@link Integer})，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Integer getIntegerOrNull(String key){
		try {
			return getInteger(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getBoolean(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取({@link Boolean})，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Boolean getBooleanOrNull(String key){
		try {
			return getBoolean(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getBytes(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取字节数组，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public byte[] getBytesOrNull(String key){
		try {
			return getBytes(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getByte(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Byte}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Byte getByteOrNull(String key){
		try {
			return getByte(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getShort(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Short}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Short getShortOrNull(String key){
		try {
			return getShort(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getLong(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Long}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Long getLongOrNull(String key){
		try {
			return getLong(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getFloat(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Float}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Float getFloatOrNull(String key){
		try {
			return getFloat(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getDouble(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Double}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Double getDoubleOrNull(String key){
		try {
			return getDouble(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getBigDecimal(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link BigDecimal}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public BigDecimal getBigDecimalOrNull(String key){
		try {
			return getBigDecimal(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getDate(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Date}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Date getDateOrNull(String key){
		try {
			return getDate(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getSqlDate(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Date}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Date getSqlDateOrNull(String key){
		try {
			return getSqlDate(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 代理 {@link JSONObject#getTimestamp(String)}方法,
	 * 从{@link JSONObject}中根据{@code key}获取{@link Timestamp}，
	 * 解析失败则返回{@code null}
	 * @param key
	 */
	public Timestamp getTimestampOrNull(String key){
		try {
			return getTimestamp(key);
		} catch (JSONException e) {
			logger.debug(e.getMessage());
			return null;
		}
	}
	/**
	 * 将{@link JSONObject}封装为{@link JSONObjectDecorator}
	 * @param jsonObject
	 */
	public static JSONObjectDecorator wrap(JSONObject jsonObject){
		if(jsonObject instanceof JSONObjectDecorator){
			return (JSONObjectDecorator)jsonObject;			
		}
		return new JSONObjectDecorator(jsonObject);
	}
	/**
	 * 从{@link JSONObjectDecorator}为获取封装的{@link JSONObject}对象
	 * @param jsonObject
	 */
	public static JSONObject unwrap(JSONObject jsonObject){
		if(jsonObject instanceof JSONObjectDecorator){
			return unwrap(((JSONObjectDecorator)jsonObject).getDelegate());			
		}
		return jsonObject;
	}
}
